/**
Draws the Circles, game won banner and game lost banner
*/
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JPanel;
import javax.swing.Timer;

class GameBoard extends JPanel implements ActionListener{

        private static final long serialVersionUID = 1553697124437310276L;
        public final int[] currentCircle = { 0 };
        private double time;

        @Override
/**
Prints the GameOver or GameWinner Banners
@param g The Graphics panel seen by the user
@see GameOver if game is over
@see GameWinner if game is won
*/
        protected void paintComponent(Graphics g) {
   int a = (int) (Math.random()*100);
                int z = a;
                int x = (int) (Math.random()*getWidth());
                int y = (int) (Math.random()*getHeight());
                int red = (int) (Math.random()*255);
                int green = (int) (Math.random()*255);
                int blue = (int) (Math.random()*255);
                Color c = new Color(red, green, blue);
                g.setColor(c);
                g.fillOval(x, y, z, a);
                draw((Graphics2D) g);
                if (model.isGameOver()) {
                        printGameOver((Graphics2D) g);
                }
                if (model.isGameWon()) {
                        printGameWinner((Graphics2D) g);
                }
        }
/**
Prepares the GameOver banner to be printed 
@param g2 The Graphics2D type that shows a graphics panel to the user
*/
        private void printGameOver(Graphics2D g2) {
                int w = getWidth();
                int h = getHeight();
                int w2 = w / 2;
                int h2 = h / 2;
                String text = "GAME OVER";
                Font font = new Font("Impact", Font.BOLD, 16);
                g2.setFont(font);
                FontMetrics fm = g2.getFontMetrics();
                Rectangle2D rect = fm.getStringBounds(text, g2);
                g2.setColor(Color.RED);
                AffineTransform orig = g2.getTransform();
                g2.translate(w2, h2);
                g2.drawChars(text.toCharArray(), 0, text.toCharArray().length,
                                (int) (-2 * rect.getHeight()), (int) (rect.getHeight() / 2));
                g2.setTransform(orig);
        }
/**
Prepares the GameWinner banner to be printed 
@param g2 The Graphics2D type that shows a graphics panel to the user
*/
          private void printGameWinner(Graphics2D g2) {
                int w = getWidth();
                int h = getHeight();
                int w2 = w / 2;
                int h2 = h / 2;
                String text = "You Win!";
                Font font = new Font("Courier", Font.BOLD, 16);
                g2.setFont(font);
                FontMetrics fm = g2.getFontMetrics();
                Rectangle2D rect = fm.getStringBounds(text, g2);
                g2.setColor(Color.GREEN);
                AffineTransform orig = g2.getTransform();
                g2.translate(w2, h2);
                g2.drawChars(text.toCharArray(), 0, text.toCharArray().length,
                                (int) (-2 * rect.getHeight()), (int) (rect.getHeight() / 2));
                g2.setTransform(orig);
        }
        private final DataModel model;

/**
Sets clock for the panel to be repainted
@param model Type DataModel that has a clock
*/

        public GameBoard(DataModel model) {
                this.model = model;
      time = 0;
            Timer clock = new Timer(1, this); 
            clock.start();
        }
/**
Sets interval for the panel to be repainted
@param e Type ActionEvent
*/
        public void actionPerformed(ActionEvent e)
        {
                time += .25;
            repaint();
        }

        // draw must be called by paintComponent of the panel
        /**
         * Draws the circles in the gameboard. Recolors selected circle to yellow.
         * 
         * @param graphics
         *            panel of type Graphics2D
         */
        private void draw(Graphics2D g2) {
                int w = getWidth();
                int h = getHeight();
                int w2 = w / 2;
                int h2 = h / 2;
                int radiusStep = Math.min(w, h) / ((DataModel.NUM_CIRCLES + 1) * 2);
                int radiusStep2 = radiusStep / 2;
                double offsetAngle = Math.PI / (DataModel.NUM_SECTORS);

                // Anti-Aliasing
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);

                g2.setStroke(new BasicStroke(3));

                // Draw rings, leaving space for a smaller, inner circle.
                for (int i = DataModel.NUM_CIRCLES - 1; i >= 0; i--) {
                        int radius = radiusStep * (i + 2);
                        // If it is the first circle, fill in the oval.

                        g2.setColor(Color.GRAY);
                        g2.drawOval(w2 - radius, h2 - radius, 2 * radius, 2 * radius);

                        // Draw segments.
                        for (int j = 0; j < DataModel.NUM_SECTORS; j++) {
                                char[] chars = model.getCellText(i, j);
                                int val = model.getCellValue(i, j);
                                if (val == 0) {
                                        g2.setColor(Color.LIGHT_GRAY);
                                        if (i == currentCircle[0] - 1)
                                                g2.setColor(Color.YELLOW);
                                } else {
                                        g2.setColor(getSectorColor(val));
                                        if (i == currentCircle[0] - 1) {
                                                g2.setColor(Color.YELLOW);
                                                // g2.setColor(getSectorColor(val + 1));
                                        }

                                }
                                Arc2D arc = new Arc2D.Double(w2 - radius, h2 - radius,
                                                2 * radius, 2 * radius, (j - 1) * 45, 45, Arc2D.PIE);
                                g2.fill(arc);
                                if (i == currentCircle[0] - 1)
                                        g2.setColor(Color.YELLOW);
                                else
                                        g2.setColor(getBorderColor(val));
                                g2.draw(arc);

                                // Set Font
                                Font font = new Font("Impact", Font.BOLD, 16);
                                g2.setFont(font);

                                FontMetrics fm = g2.getFontMetrics();
                                Rectangle2D rect = fm.getStringBounds(chars.toString(), g2);
                                if(i == currentCircle[0] - 1)
                                	g2.setColor(Color.BLACK);
                                else
                                	g2.setColor(getFontColor(val));
                                AffineTransform orig = g2.getTransform();
                                // Bring origin to the center
                                // Rotate to proper sector angle
                                // Translate into proper ring
                                // Rotate 90 degrees
                                g2.translate(w2, h2);
                                g2.rotate(-Math.PI * j / DataModel.NUM_CIRCLES + offsetAngle);
                                g2.translate(radius - radiusStep2, 0);
                                // rotate number to be facing bottom-into center of circle
                                g2.rotate(Math.PI / 2);
                                g2.drawChars(chars, 0, chars.length,
                                                (int) (-rect.getHeight() / 2),
                                                (int) (rect.getHeight() / 2));
                                g2.setTransform(orig);
                        }
                }

                // Clip output to largest circle.
                int radius = radiusStep * (DataModel.NUM_CIRCLES + 1);
                Ellipse2D clipOval = new Ellipse2D.Float();
                // clipOval.setFrame(0, 0, w, h);
                clipOval.setFrame(w2 - radius, h2 - radius, 2 * radius, 2 * radius);
                g2.clip(clipOval);

                g2.setColor(Color.GRAY);
                g2.drawLine(0, h2, w, h2); // Horizontal line.
                g2.drawLine(w2, 0, w2, h); // Vertical line.
                // g2.drawLine(0, 0, w, h); // Left diagonal.
                int radius45 = (int) (radius * Math.sqrt(2));
                g2.drawLine(w2 - radius45, h2 - radius45, w2 + radius45, h2 + radius45); // Left
                                                                                                                                                                        // diagonal.
                g2.drawLine(w2 - radius45, h2 + radius45, w2 + radius45, h2 - radius45); // Right
                                                                                                                                                                        // diagonal.
                // Draw the center circle, unused for data.
                g2.fillOval(w2 - radiusStep + 1, h2 - radiusStep + 1,
                                2 * radiusStep + 1, 2 * radiusStep + 1);
        }

/**
Generates the color for the tile depending on which number is on the tile
@param  value  The number on the tile
@return   the Color that will be used to paint the tile
*/


        private Color getSectorColor(int value) {
                switch (value) {
                case 2:
                        return new Color(0xCEECF5);

                case 4:
                        return new Color(0xA9E2F3);

                case 8:
                        return new Color(0x81BEF7);

                case 16:
                        return new Color(0x5882fa);

                case 32:
                        return new Color(0x1d41db);

                case 64:
                        return new Color(0x12288a);

                case 128:
                        return new Color(0x6822cf);

                case 256:
                        return new Color(0xb71acf);

                case 512:
                        return new Color(0xe124f3);

                case 1024:
                        return new Color(0xcf1577);

                case 2048:
                        return new Color(0x660000);

                default:
                        return Color.WHITE;
                }
        }

/**
Generates the color for the font of the tile depending on which number is on the tile
@param  value  The number on the tile
@return   the Color that will be used for the font of the number on the tile
*/
        private Color getFontColor(int value) {
                switch (value) {
                case 2:
                case 4:
                case 8:
                        return new Color(0x12288a);
                default:
                        return Color.WHITE;
                }
        }

/**
Generates the color for the border of the tile depending on which number is on the tile
@param  value  The number on the tile
@return   the Color that will be used for the border of the tile
*/

        private Color getBorderColor(int value) {
                switch (value) {

                case 1:
                        return Color.yellow;

                case 2:
                        return new Color(0xb5edfd);

                case 4:
                        return new Color(0x84c2fc);

                case 8:
                        return new Color(0x5eaffa);

                case 16:
                        return new Color(0x264de8);

                case 32:
                        return new Color(0x223690);

                case 64:
                        return Color.BLACK;

                case 128:
                        return new Color(0x6a22d2);

                case 256:
                        return new Color(0x7d37ab);

                case 512:
                        return new Color(0x7a254f);

                case 1024:
                        return new Color(0xb50d5b);

                case 2048:
                        return new Color(0xcc1040ff);

                default:
                        return Color.GRAY;
                }
        }
		
}